/*
 * Copyright (c) 2009, Hamish Morgan. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the University of Sussex nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package locusts.client.diamondtouch;

import de.sciss.net.OSCMessage;
import java.io.Serializable;
import java.util.Date;
import java.util.EventObject;

/**
 * Abstract super-class for all DiamonTouch event objects, providing common
 * field storage and methods.
 *
 * Common protocol header is:
 * String:      name    (/DT...)
 * Integer:     table width   (eg 2032)
 * Integer:     table height  (eg 1520)
 * Integer:     userId  (0...7)
 * 
 * @author Hamish Morgan
 */
public abstract class DTEvent extends EventObject 
        implements Serializable, Cloneable {

    //
    protected transient static final String MESSAGE_PREFIX = "/DT";
    private transient static final int MIN_USER_ID = 0;
    private transient static final int MAX_USER_ID = 7;
    //
    private final int userId;
    private final long time;

    /**
     * Construct a new DTMessage object from the given arguments.
     *
     * @param source
     * @param userId        The user that origionated this message.
     * @param time          The timestampt of when this event was fired.
     * @throws IllegalArgumentException when any of the arguments are outside
     *                      of their expected range.
     */
    protected DTEvent(DTHandler source,  int userId, long time)
            throws IllegalArgumentException {
        super(source);
        if (userId < MIN_USER_ID || userId > MAX_USER_ID)
            throw new IllegalArgumentException(
                    "UserId should be an integer between " + MIN_USER_ID +
                    " and " + MAX_USER_ID + ", found: " + userId);
        this.userId = userId;
        this.time = time;
    }

    /**
     * Constructor that clones the <tt>DTEvent</tt> object parameter.
     * 
     * @param other the <tt>DTEvent</tt> to clone
     */
    protected DTEvent(DTEvent other) {
        super(other.source);
        this.userId = other.userId;
        this.time = other.time;
    }

 
    /**
     * The table assigned user ID, representing the mat that person is
     * standing on. Will be in the range 0 to 7.
     *
     * @return the user id
     */
    public int getUserId() {
        return userId;
    }

    /**
     * The time the OSC event was received from DTBridge.
     *
     * @return the time the event occured.
     */
    public long getTime() {
        return time;
    }

    @Override
    public DTHandler getSource() {
        return (DTHandler) super.getSource();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) return false;
        if (getClass() != obj.getClass()) return false;
        final DTEvent other = (DTEvent) obj;
        if (this.userId != other.userId) return false;
        if (this.time != other.time) return false;
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 89 * hash + this.userId;
        hash = 89 * hash + (int) (this.time ^ (this.time >>> 32));
        return hash;
    }

    @Override
    public String toString() {
        final StringBuffer buf = new StringBuffer();
        buf.append(super.toString());
        buf.append('[');
        buf.append("time=").append(new Date(time));
        buf.append(", userId=").append(userId);
        buf.append(']');
        return buf.toString();
    }
}
